.. _глава_65_start:

Pragma
=======

.. index::
    pragma

Прагмы - это способ взаимодействия с компилятором. Они могут использоваться как для предоставления
специальной информации компилятору, так и для получения информации от него.
Хотя они полезны и в нешаблонном коде, pragma(msg) может быть полезна
полезной при отладке шаблонов.
Каждый производитель компилятора волен вводить свои специальные директивы pragma в дополнение к
в дополнение к следующим обязательным:

pragma(msg)
-----------

Печатает сообщение на stderr во время компиляции. Во время
выполнения скомпилированной программы вывода сообщений нет
Например, следующая pragma(msg) используется для раскрытия типов
параметров шаблона, предположительно при отладке:

.. code-block:: d

    import std.string;

    void func(A, B)(A a, B b)
    {
        pragma(msg, format("Called with types '%s' and '%s'",
                A.stringof, B.stringof));
        // ...
    }

    void main()
    {
        func(42, 1.5);
        func("hello", 'a');
    }

.. code-block:: console

    Called with types 'int' and 'double'
    Called with types 'string' and 'char'

pragma(lib)
-----------

Указывает компилятору связать программу с определенной библиотекой. Это
самый простой способ связать программу с библиотекой, которая уже установлена в
системе.
Например, следующая программа будет скомпонована с библиотекой curl
без необходимости упоминания библиотеки в командной строке:

.. code-block:: d

    import std.stdio;
    import std.net.curl;

    pragma(lib, "curl");
    void main()
    {
        // Get this chapter
        writeln(get("ddili.org/ders/d.en/pragma.html"));
    }

pragma(inline)
--------------

Определяет, должна ли функция быть встроенной или нет.
Каждый вызов функции имеет определенные затраты на производительность. Вызов функции включает в себя передачу
аргументов в функцию, возврат возвращаемого значения вызывающей стороне и обработку
некоторую бухгалтерскую информацию, чтобы запомнить, откуда была вызвана функция
чтобы можно было продолжить выполнение после возврата функции.
Эти затраты обычно незначительны по сравнению с затратами на реальную работу, которую выполняют
вызывающая и вызываемая функции. Однако в некоторых случаях один только акт вызова
определенной функции может оказать заметное влияние на производительность программы.
Это может произойти, особенно если тело функции относительно быстрое и если она
вызывается из короткого цикла, который повторяется много раз.
Следующая программа вызывает небольшую функцию из цикла и увеличивает
счетчик, когда возвращаемое значение удовлетворяет условию:

.. code-block:: d

        import std.stdio;
        import std.datetime.stopwatch;

        // A function with a fast body:
        ubyte compute(ubyte i)
        {
            return cast(ubyte)(i * 42);
        }

        void main()
        {
            size_t counter = 0;
            StopWatch sw;
            sw.start();
            // A short loop that repeats many times:
            foreach (i; 0 .. 100_000_000)
            {
                const number = cast(ubyte) i;
                if (compute(number) == number)
                {
                    ++counter;
                }
            }
            sw.stop();
            writefln("%s milliseconds", sw.peek.total!"msecs");
        }

Код использует преимущества std.datetime.stopwatch.StopWatch для измерения
время выполнения всего цикла:

.. code-block:: console

    674 milliseconds

Ключ компилятора -inline указывает компилятору выполнить оптимизацию компилятора
оптимизацию, называемую инлайнингом функций:

.. code-block:: console

    $  dmd deneme.d -w -inline

Когда функция инлайнится, ее тело вставляется в код прямо в том месте, откуда она вызывается
из которой она вызывается; фактического вызова функции не происходит. Ниже приведен эквивалентный код, который
который компилятор скомпилирует после инлайнинга:

.. code-block:: d

    // An equivalent of the loop when compute() is inlined:
    foreach (i; 0 .. 100_000_000)
    {
        const number = cast(ubyte) i;
        const result = cast(ubyte)(number * 42);
        if (result == number)
        {
            ++counter;
        }
    }

На платформе, где я тестировал эту программу, устранение вызова функции сократило
время выполнения примерно на 40 %.:abbr:

.. code-block:: d

    407 milliseconds

Хотя может показаться, что раскрытие функций в коде - это большой выигрыш, такая
оптимизация подходит не для всех ситуаций, поскольку выпадающие функции могут привести к разрастанию кода
разрастаться и переполнять кэш кода микропроцессора.
В результате код может, наоборот, выполняться медленнее. По этой причине функции
Решение о том, открывать ли их в коде, обычно остается за компилятором с опцией -inline.
Однако в некоторых случаях можно помочь компилятору в принятии этого решения.
Для этого используется прагма inline:
* pragma(inline, false): Даже если используется опция компилятора -inline
указывает на то, что определенные функции не должны быть открыты в коде.
* pragma(inline, true): Когда используется опция компилятора -inline, определенные
функции должны быть явно объявлены в коде. Это
Ошибки компиляции возникают, когда оптимизация не может быть применена (это включает в себя
Однако то, как именно работает эта прагма, зависит от конкретного компилятора.
может варьироваться).
*  pragma(inline): Решение открывать в сценарий с помощью опции -inline командной строки
строки, независимо от того, указана она в строке или нет, предоставляется компилятору.
Эти прагмы могут влиять на функцию, в которой они встречаются, или могут влиять на несколько функций.
влиять на область видимости скобок или двоеточий


.. code-block:: d

      pragma(inline, false)
      {
          // Functions defined in this scope should not be inlined
          // ...
      }
      int foo()
      {
          pragma(inline, true); // This function should be inlined
          // ...
      }

      pragma(inline, true):
      // Functions defined in this section should be inlined
      // ...
      pragma(inline):
      // Functions defined in this section should be inlined or not
      // depending on the -inline compiler switch
      // ...

Еще один ключ компилятора, который может ускорить выполнение программ, - это -O, который
который предписывает компилятору выполнять больше алгоритмов оптимизации. Однако более высокая
скорость работы программ достигается за счет более низкой скорости компиляции, поскольку эти
алгоритмы занимают значительное количество времени.

pragma(startaddress)
--------------------
Указывает стартовый адрес программы. Поскольку стартовый адрес обычно
назначается средой выполнения D, очень маловероятно, что вы когда-либо будете использовать
эту прагму.

pragma(mangle)
---------------

Указывает, что символ должен быть приведен в соответствие с именем, отличным от стандартного
метода преобразования имен. Упорядочивание имен - это то, как компоновщик идентифицирует
функций и их вызывающих. Эта прагма полезна, когда D-коду нужно вызвать
библиотечную функцию, которая, как оказалось, является ключевым словом D.
Например, если в библиотеке C есть функция с именем override, то поскольку override
является ключевым словом в D, то единственный способ вызвать ее из D - это
другое имя. Однако это другое имя все равно должно быть преобразовано в
реальное имя функции в библиотеке, чтобы компоновщик смог ее идентифицировать:

.. code-block:: d

      /* If a C library had a function named 'override', it could
      * only be called from D through a name like 'c_override',
      Pragmas
      416
      * mangled as the actual function name: */
      pragma(mangle, "override")
      extern (C) string c_override(string);
      void main()
      {
      /* D code calls the function as c_override() but the
      * linker would find it by its correct C library name
      * 'override': */
          auto s = c_override("hello");
      }
